Caveman's playlists
Автор: caveman
Версия: 1.01
Тип: работа с игровой музыкой




Описание:

Скрипт позволяет создавать плейлисты BGM для игры и управлять ими.
При запуске, треки проигрываются последовательно (либо шаффлом) до новых команд.
Подробное описание доступных команд и пример заполнения есть прямо в скрипте.

Скрипт:
Спойлер Код:

Код:
#:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:
# Caveman's playlists
# Version: 1.01
# Author : Caveman
#:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:
# Использование:
#
# Скрипт позволяет создавать плейлисты BGM для игры и управлять ими.
# При запуске, треки проигрываются последовательно (либо шаффлом) до
# новых команд.
#
# 1) Плейлист состоит из хэша: 'название' => список 
# название_песни=длительность в виде mm:ss, как тут
#  'night' => "
#    brinkoftime=2:17
#    bottomofnight=3:39
#    "
# Пример чуть ниже, в PL_MANAGER
#
# 2) Поддерживаются форматы mp3, mid, ogg, wav; но функция паузы
# из-за особенностей движка работает только для ogg и wav
#
# 3) При загрузке игры автоматом загружается менеджер плейлистов, берущий
# плейлисты из хэша CV_PLAYLIST::PL_MANAGER, и проверяет наличие треков
# из плейлистов в папке Audio/BGM/
#
# 4) Доступные команды:
#
# pl_manager.play_pl(pl,n) - запускает n-ый трек плейлиста с номером pl
# После окончания трека, запускается следующий (либо рандом, в зависимости
# от режима mode плейлиста). Если треки закончились (в прямом режиме), 
# плейлист начинает играть сначала.
#
# pl_manager.play(n) - запускает n-ый трек текущего плейлиста
#
# pl_manager.set_mode(n) - установка режима проигрывания
# n=0 - прямой
# n=1 - шаффл
# 
# pl_manager.next - играет следующий либо рандомный трек плейлиста
#
# pl_manager.prev - играет предыдущий либо рандомный трек плейлиста
#
# pl_manager.stop - остановка проигрывания
#
# pl_manager.pause - пауза (работает для ogg, wav)
#
# pl_manager.unpause - продолжить игру (работает для ogg, wav)
#
# pl_manager.volume=n - установка громкости
# n - от 0 до 100
#
# pl_manager.pitch=n - установка скорости
# n - от 50 до 150
#
# pl_manager.buffer=n - установка fade (затухания громкости) в конце песни, 
# в секундах
#
#:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:
 
($imported ||= {})[:caveman_playlists] = 1.00
 
module CV_PLAYLIST
  PL_MANAGER = { 
  'day' => "
      kvaato=00:51
      Peaceful_Days=3:57
      SecretOfTheForest=4:35
      Green_Memories=3:47
      ",
  'night' => "
    brinkoftime=2:17
    bottomofnight=3:39
    ",   
    }
 
end
 
 
 
class Song
  attr_accessor :name
  attr_accessor :length
 
  def initialize(name, length)
    self.name = name.strip
    self.length = parse(length)
  end
 
  # разбираем время вида 6:04 на секунды
  def parse(time)
    t = 0
    time.gsub(/\A(.*?):(.*?)\Z/) do
      t += $1.to_i * 60
      t += $2.to_i
    end
    return t
  end
end
 
class Playlist
  attr_accessor :name
  attr_accessor :songs
 
  def initialize(name, songs)
    self.name = name
    self.songs = songs
    @buffer = 1 # delay (+fading) between songs (sec)
    @volume = 80 # default BGM volume
    @pitch = 100 # default BGM pitch
    @mode = 0 # 0 - normal, 1 - shuffle
    @is_playing = false
    @current_song = 0
    @pos = 0
    @start_time = 0;
  end
 
  def update
    if @is_playing
      total_time = Time.now
      # время тут - сдвиг от запуска
      @pos = total_time - @start_time
      if @pos >= self.songs[@current_song].length
        # next track
        @current_song += 1
        play_new
      elsif @pos + @buffer >= self.songs[@current_song].length
        # fade
        Audio.bgm_fade(@buffer*1000) 
      end
    end
  end
 
  def play_new
    if @current_song >= songs.length
      if @mode == 0
        Audio.bgm_stop
        play(0)
      else
        p 'shuffle'
        Audio.bgm_stop
        play(rand(songs.length-1)) 
      end
    else
      if @mode == 0
        Audio.bgm_stop
        play(@current_song)
      else
        Audio.bgm_stop
        play(rand(songs.length-1)) 
      end
    end
  end
 
  def set_mode(mode)
    @mode = mode
  end
 
  def play(n)
    # PLAY n'th song
    stop
    @current_song = n
    @is_playing = true
    @start_time = Time.now
    Audio.bgm_play(sprintf("Audio/BGM/%s",self.songs[@current_song].name), @volume, @pitch, @pos)
  end
 
  def next
    @current_song += 1
    play_new
  end
 
  def prev
    @current_song -= 1
    if @current_song < 0
      @current_song = 0
    end
    play_new
  end
 
  def stop
    # STOP playlist (don't save @pos and current song)
    @current_song = 0
    @is_playing = false
    @pos = 0
    @start_time = 0
    Audio.bgm_stop 
  end
 
  def pause
    # PAUSE song (save @pos)
    @is_playing = false
    Audio.bgm_stop 
  end
 
  def unpause
    # PAUSE song (save @pos)
    @is_playing = true
    @start_time = Time.now - @pos
    Audio.bgm_play(sprintf("Audio/BGM/%s",self.songs[@current_song].name), @volume, @pitch, @pos)
  end
 
  def pitch
    @pitch
  end
 
  def pitch=(pitch)
    @pitch = pitch
    if @pitch < 50
      @pitch = 50
    end
    if @pitch > 150
      @pitch = 150
    end
 
    if @is_playing
      Audio.bgm_play(sprintf("Audio/BGM/%s",self.songs[@current_song].name), @volume, @pitch, @pos) 
    end
  end
 
  def volume
    @volume
  end
 
  def volume=(volume)
    @volume = volume
    if @volume < 0
      @volume = 0
    end
    if @volume > 100
      @volume = 100
    end
 
    if @is_playing
      Audio.bgm_play(sprintf("Audio/BGM/%s",self.songs[@current_song].name), @volume, @pitch, @pos) 
    end
  end
 
  def buffer=(buffer)
    @buffer = buffer
  end
 
  def test
    @songs.each {|song|
      if !FileTest.exist?(sprintf("Audio/BGM/%s.mp3",song.name)) and
         !FileTest.exist?(sprintf("Audio/BGM/%s.ogg",song.name)) and
         !FileTest.exist?(sprintf("Audio/BGM/%s.wav",song.name)) and
         !FileTest.exist?(sprintf("Audio/BGM/%s.mid",song.name))
 
        p sprintf("Не найден файл %s", song.name)
      end
    }
    return true
  end
end
 
class PL_Manager
  attr_accessor :playlists
 
  # INNER METHODS
  def initialize(data)
    # load from array and test exists
    load(data)
    test
    # set init pl
    @current_pl = 0
  end
 
  def load(data)
    self.playlists = []
    data.each {|d| load_pl(d) }
  end
 
  def load_pl(data)   
    name = data[0]
    songs = []
    data[1].to_s.split(/\n/).each {|a| 
      a.gsub(/\A(.*?)=(.*?)\Z/) do
        song = Song.new($1.to_s, $2.to_s)
        songs.push(song)
      end
    }
 
    self.playlists.push(Playlist.new(name, songs))
  end
 
  def update
    self.playlists[@current_pl].update
  end
 
  # METHODS FOR USE
  def play_pl(pl, n)
    @current_pl = pl
    play(n)
  end
 
  def play(n)
    self.playlists[@current_pl].play(n)
  end
 
  def stop
    self.playlists[@current_pl].stop
  end
 
  def pause
    self.playlists[@current_pl].pause
  end
 
  def unpause
    self.playlists[@current_pl].unpause
  end
 
  def pitch
    self.playlists[@current_pl].pitch
  end
 
  def pitch=(pitch)
    self.playlists[@current_pl].pitch = pitch
  end
 
  def volume
    self.playlists[@current_pl].volume
  end
 
  def volume=(volume)
    self.playlists[@current_pl].volume = volume
  end
 
  def buffer=(buffer)
    self.playlists[@current_pl].buffer = buffer
  end
 
  def test
    self.playlists.each {|pl| pl.test }
  end
 
  def set_mode(n)
    self.playlists[@current_pl].set_mode(n)
  end
 
  def next
    self.playlists[@current_pl].next
  end
 
  def prev
    self.playlists[@current_pl].prev
  end
end
 
class Game_System
  #--------------------------------------------------------------------------
  # * Playlist manager
  #--------------------------------------------------------------------------
  attr_accessor :pl_manager
  #--------------------------------------------------------------------------
  # * init_pl_manager
  #--------------------------------------------------------------------------
  def init_pl_manager
    @pl_manager = PL_Manager.new(CV_PLAYLIST::PL_MANAGER) 
  end
  #--------------------------------------------------------------------------
  # * initialize
  #--------------------------------------------------------------------------
  def initialize
    @save_disabled = false
    @menu_disabled = false
    @encounter_disabled = false
    @formation_disabled = false
    @battle_count = 0
    @save_count = 0
    @version_id = 0
    @window_tone = nil
    @battle_bgm = nil
    @battle_end_me = nil
    @saved_bgm = nil
    init_pl_manager
  end
end
 
class Scene_Base
  alias tm_update update
  def update
    tm_update
    if $game_system.pl_manager != nil
      $game_system.pl_manager.update
    end
  end
end
 
class Game_Interpreter
  def pl_manager
    return $game_system.pl_manager
  end
end


Также прикладываю демку с подсказками и описанием команд
http://yadi.sk/d/ehaPx9WnNFeGd

Скрипт будет еще дорабатываться (в частности, решать, что делать в боях, и при сейве/загрузке), ну и также приветствуются идеи и просьбы в коментах.